﻿using Castle.DynamicProxy;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace DesignPatterns.ProxyPatterns
{
    class ProxyPattern
    {
        void Main(string[] args)
        {
            //简单代理模式，调度者必须创建真实角色，没法隐藏隔离真实角色

            //实例化真实角色1
            ISubject sbj1 = new RealSubject1();
            sbj1.request();
            //实例化代理1
            ISubject pro1 = new Proxy1(sbj1);
            pro1.request();

            //普通代理模式，调度者无需知道真实角色，减少了低层次代码对高层次代码的影响，真实角色随意改动也不影响此处代理的调用
            //一般情况下，会通过团队内部规范约定，禁止直接new出真实角色，而不是代码约束，否则非常不利于系统维护
            Proxy2 pro2 = new Proxy2("proxy2");
            pro2.request();

            //强制代理模式
            ISubject2 sbj3 = new RealSubject3("boy");
            //角色绕过代理执行，会被禁止操作
            sbj3.request();
            //自己new出来的代理，也会被禁止操作
            ISubject2 pro3 = new Proxy3(sbj3);
            pro3.request();
            //只有角色指定的代理，才能够操作
            ISubject2 pro3_2 = sbj3.getProxy();
            pro3_2.request();

            //扩展修改代理，完全不影响高层代码的调用
            ISubject pro4 = new Proxy4(sbj1);
            //调用该代理，会记录并收取费用
            pro4.request();

            //动态代理，不修改高层代码，直接aop拦截
            var Generator = new ProxyGenerator();
            ISubject dynamicproxy = Generator.CreateInterfaceProxyWithoutTarget<ISubject>(new DynamicInterceptor());
            dynamicproxy.request();
            Console.Read();
        }
    }

    /// <summary>
    /// 抽象主题
    /// </summary>
    public interface ISubject {
        void request();
    }

    /// <summary>
    /// 简单角色
    /// </summary>
    public class RealSubject1 : ISubject
    {
        public void request()
        {
            Console.WriteLine("Player1 request");
        }
    }

    /// <summary>
    /// 简单代理
    /// </summary>
    public class Proxy1 : ISubject
    {
        private ISubject subject = null;

        public Proxy1() {
            subject = new Proxy1();
        }

        public Proxy1(ISubject sub) {
            subject = sub;
        }
        public void request()
        {
            BeforeRequest();
            subject.request();
            AfterRequest();
        }
        /// <summary>
        /// 预处理
        /// </summary>
        private void BeforeRequest() { }
        /// <summary>
        /// 善后处理
        /// </summary>
        private void AfterRequest() { }
    }

    /// <summary>
    /// 普通角色
    /// </summary>
    public class RealSubject2: ISubject
    {
        private string name = "";
        public RealSubject2(ISubject _sbj, string _name) {
            if (_sbj == null)
                throw new Exception("无法创建真实角色");
            else
                name = _name;
        }

        public void request() { }
    }

    /// <summary>
    /// 普通代理
    /// 无需将整个角色传入，就可以调用代理，用户无需关心代理是谁，傻瓜式操作
    /// </summary>
    public class Proxy2 : ISubject
    {
        ISubject subject = null;
        public Proxy2(string _name) {
            try
            {
                subject = new RealSubject2(this, _name);
            }
            catch {
            }
        }
        public void request()
        {
            BeforeRequest();
            subject.request();
            AfterRequest();
        }
        /// <summary>
        /// 预处理
        /// </summary>
        private void BeforeRequest() { }
        /// <summary>
        /// 善后处理
        /// </summary>
        private void AfterRequest() { }
    }

    /// <summary>
    /// 强制代理抽象主题
    /// </summary>
    public interface ISubject2 {
        void request();
        ISubject2 getProxy();
    }

    /// <summary>
    /// 强制角色
    /// 用户必须指定自己选定的代理，才可以由代理操作，对用户要求较高
    /// </summary>
    public class RealSubject3 : ISubject2
    {
        private string name = "";
        private ISubject2 proxy;
        public RealSubject3(string _name) {
            this.name = _name;
        }
        public ISubject2 getProxy()
        {
            if (this.proxy == null)
                this.proxy = new Proxy3(this);
            return this.proxy;
        }

        public void request()
        {
            if (!HasProxy())
                throw new Exception("请使用您的指定代理");
        }

        private bool HasProxy() {
            return this.proxy != null;
        }
    }

    /// <summary>
    /// 强制代理
    /// 从强制代理的真实角色那获取的代理才可以调用，自行new出来的不行
    /// </summary>
    public class Proxy3 : ISubject2
    {
        private ISubject2 subject;
        public Proxy3(ISubject2 sbj) {
            this.subject = sbj;
        }
        public ISubject2 getProxy()
        {
            return this;
        }

        public void request()
        {
            this.subject.request();
        }
    }

    /// <summary>
    /// 个性代理抽象接口，作用类似AOP
    /// </summary>
    public interface IProxy {
        void count();
    }

    /// <summary>
    /// 个性代理产生的真实代理
    /// 每次请求都会被抽象代理接口拦截并调用其方法
    /// </summary>
    public class Proxy4 : ISubject, IProxy
    {
        public void count()
        {
            Console.WriteLine("每次找代理请求，代理都要收取一次费用");
        }
        private ISubject subject = null;

        public Proxy4()
        {
            subject = new Proxy1();
        }

        public Proxy4(ISubject sub)
        {
            subject = sub;
        }
        public void request()
        {
            subject.request();
            count();
        }
    }
    
    /// <summary>
    /// 基于castle的动态代理拦截器
    /// </summary>
    public class DynamicInterceptor : IInterceptor
    {
        private void beforedoing() { }

        private void afterdone() { }
        public void Intercept(IInvocation invocation)
        {

            if (invocation.InvocationTarget != null) {
                beforedoing();
                invocation.Proceed();
                afterdone();
            }
        }
    }
}
